package com.ideal.manage.esms.service.monitor;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.ideal.manage.esms.bean.diagnostic.DiagnoseResultInfo;
import com.ideal.manage.esms.bean.diagnostic.QDiagnoseResultBatch;
import com.ideal.manage.esms.bean.diagnostic.QDiagnoseResultInfo;
import com.ideal.manage.esms.bean.esms.EsmsDataBatch;
import com.ideal.manage.esms.bean.esms.EsmsIntegration;
import com.ideal.manage.esms.bean.esms.QEsmsDataBatch;
import com.ideal.manage.esms.bean.esms.QEsmsIntegration;
import com.ideal.manage.esms.bean.project.EquipmentManage;
import com.ideal.manage.esms.bean.project.ProjectManage;
import com.ideal.manage.esms.bean.project.QEquipmentManage;
import com.ideal.manage.esms.jpa.JpaRepositoryImpl;
import com.ideal.manage.esms.service.ElasticsearchService;
import com.ideal.manage.esms.util.IntegrationUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.queryparser.xml.builders.BooleanQueryBuilder;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.InternalDateHistogram;
import org.elasticsearch.search.aggregations.metrics.avg.InternalAvg;
import org.elasticsearch.search.sort.SortOrder;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.util.*;

@Service
@Transactional
public class MonitorBlockChartService {
    private JpaRepositoryImpl<EsmsIntegration, Long> integrationRepository;
    private JpaRepositoryImpl<ProjectManage, String> projectManageRepository;
    private JpaRepositoryImpl<EquipmentManage, String> equipmentManageRepository;
    private JpaRepositoryImpl<DiagnoseResultInfo, String> diagnoseResultInfoRepository;
    private JpaRepositoryImpl<EsmsDataBatch, Long> dataBatchRepository;
    @Autowired
    private ElasticsearchService elasticsearchService;

    @Autowired
    private EntityManager entityManager;
    @Autowired
    private TransportClient transportClient;

    @PostConstruct
    public void init() {
        this.integrationRepository = new JpaRepositoryImpl<>(EsmsIntegration.class, entityManager);
        this.projectManageRepository = new JpaRepositoryImpl<>(ProjectManage.class, entityManager);
        this.equipmentManageRepository = new JpaRepositoryImpl<>(EquipmentManage.class, entityManager);
        this.diagnoseResultInfoRepository = new JpaRepositoryImpl<>(DiagnoseResultInfo.class, entityManager);
        this.dataBatchRepository = new JpaRepositoryImpl<EsmsDataBatch, Long>(EsmsDataBatch.class, entityManager);
    }


    public JSONObject getTodayElectricity(String id) {
        JSONObject r = new JSONObject();
        ProjectManage projectManage = projectManageRepository.findOne(id);
        if (projectManage == null) {
            return r;
        }
        LocalDateTime startTime = LocalDateTime.of(LocalDate.now(), LocalTime.of(0, 0, 0));
        LocalDateTime endTime = startTime.plusHours(23).withMinute(59).withSecond(59);
        Date startDate = Date.from(startTime.toInstant(ZoneOffset.of("+8")));
        Date endDate = Date.from(endTime.toInstant(ZoneOffset.of("+8")));

        String sql = "SELECT DATE_FORMAT(cal_time, '%Y-%m-%d %H') AS cal_time1, sum(val) FROM esms_integration" +
                " WHERE cal_time BETWEEN ? AND ? AND type=? AND project_ip=? GROUP BY cal_time1";

        JSONObject charge = Utils.getHour();
        //充电量
        Query qry = entityManager.createNativeQuery(sql);
        qry.setParameter(1, startDate);
        qry.setParameter(2, endDate);
        qry.setParameter(3, "cdl");
        qry.setParameter(4, projectManage.getIp());
        List<Object[]> list = qry.getResultList();
        for (Object[] objects : list) {
            charge.put((String) objects[0], objects[1]);
        }
        r.put("charge", charge);

        //放电量
        JSONObject discharge = Utils.getHour();
        qry.setParameter(3, "fdl");
        list = qry.getResultList();
        for (Object[] objects : list) {
            discharge.put((String) objects[0], objects[1]);
        }
        sumReduceCount(list.size(), discharge);
        r.put("discharge", discharge);

        //省电费
        JSONObject sdf = Utils.getHour();
        qry.setParameter(3, "sdf");
        list = qry.getResultList();
        for (Object[] objects : list) {
            sdf.put((String) objects[0], objects[1]);
        }
        sumReduceCount(list.size(), sdf);
        r.put("sdf", sdf);

        //耗电费
        JSONObject dischargePrice = Utils.getHour();
        qry.setParameter(3, "hdf");
        list = qry.getResultList();
        for (Object[] objects : list) {
            dischargePrice.put((String) objects[0], objects[1]);
        }
        sumReduceCount(list.size(), dischargePrice);
        r.put("dischargePrice", dischargePrice);
        r.put("x", Utils.nowHour());
        return r;
    }

    protected void sumReduceCount(int size, JSONObject r) {
        List<String> sortKeys = new ArrayList<>(r.keySet());
        Collections.sort(sortKeys);
        double sum = 0.0;
        for (int i = 0; i < size; i++) {
            String key = sortKeys.get(i);
            sum += r.getDoubleValue(key);
            r.put(key, sum);
        }
    }


    public JSONObject getPackageTodayLine(String id) {
        // 找到电池包
        EquipmentManage equipmentManage = equipmentManageRepository.findOne(id);
        Tuple<Date, Date> todayRange = Utils.getTodayRange();
        Date startDate = todayRange.v1();
        Date endDate = todayRange.v2();

        JSONObject r = Utils.nowHour();
        JSONObject queryJson = new JSONObject();
        elasticsearchService.aggregationAvg(QueryBuilders.boolQuery()
                        .filter(QueryBuilders.termQuery("macid", equipmentManage.getCode()))
                        .filter(QueryBuilders.existsQuery("BatVoltage"))
                        .filter(QueryBuilders.rangeQuery("time").gte(startDate.getTime()).lte(endDate.getTime())),
                DateHistogramInterval.hours(1), (filedName, time, val) -> {
                    String key = DateTimeFormat.forPattern("yyy-MM-dd HH").print(time);
                    JSONObject json;
                    if (queryJson.containsKey(key)) {
                        json = queryJson.getJSONObject(key);
                    } else {
                        json = new JSONObject();
                        json.put("BatVoltage", 0);
                        json.put("Soc", 0);
                    }
                    json.put("BatVoltage", val);
                    queryJson.put(key, json);
                }, "BatVoltage");

        Query query = entityManager.createNativeQuery("SELECT AVG(d.result_val) as val, FROM_UNIXTIME(time / 1000, '%Y-%m-%d %H') hours " +
                " FROM esms_diagnose_batch b,  esms_diagnose_result_info d " +
                " WHERE b.id = d.batch_id AND d.set_val = 'soc' AND b.`time` BETWEEN ? AND ? GROUP BY hours ORDER BY b.`time` DESC");
        query.setParameter(1, startDate.getTime());
        query.setParameter(2, endDate.getTime());
        List<Object[]> list = query.getResultList();
        for (Object[] values : list) {
            String key = (String) values[1];
            double val = Utils.toDouble((Double) values[0]);
            if (queryJson.containsKey(key)) {
                queryJson.getJSONObject(key).put("Soc", val);
            }
        }
        //合并
        for (String key : r.keySet()) {
            if (queryJson.containsKey(key)) {
                r.put(key, queryJson.getJSONObject(key));
            } else {
                JSONObject empty = new JSONObject();
                empty.put("BatVoltage", 0);
                empty.put("Soc", 0);
                r.put(key, empty);
            }
        }
        return r;
    }

    public JSONObject getTodayBar(String id) {
        EquipmentManage equipmentManage = equipmentManageRepository.findOne(id);
        Tuple<Date, Date> todayRange = Utils.getTodayRange();
        Date startDate = todayRange.v1();
        Date endDate = todayRange.v2();

        JSONObject total = new JSONObject();
        //温度
        elasticsearchService.aggregationAvg(QueryBuilders.boolQuery()
                        .filter(QueryBuilders.termQuery("macid", equipmentManage.getCode()))
                        .filter(QueryBuilders.existsQuery("MinTemp"))
                        .filter(QueryBuilders.rangeQuery("time").gte(startDate.getTime()).lte(endDate.getTime())),
                DateHistogramInterval.hours(1), (filedName, time, val) -> {
                    String key = DateTimeFormat.forPattern("HH:mm:ss").print(time);
                    processAggregationToday(total, filedName, val, key);
                }, "MaxTemp", "MinTemp");
        //电压
        elasticsearchService.aggregationAvg(QueryBuilders.boolQuery()
                        .filter(QueryBuilders.termQuery("macid", equipmentManage.getCode()))
                        .filter(QueryBuilders.existsQuery("MinCellVolt"))
                        .filter(QueryBuilders.rangeQuery("time").gte(startDate.getTime()).lte(endDate.getTime())),
                DateHistogramInterval.hours(1), (filedName, time, val) -> {
                    String key = DateTimeFormat.forPattern("HH:mm:ss").print(time);
                    processAggregationToday(total, filedName, val, key);
                }, "MaxCellVolt", "MinCellVolt");
        //处理极值
        JSONObject r = new JSONObject();
        for (String key : total.keySet()) {
            JSONObject data = total.getJSONObject(key);
            r.put(key, Lists.newArrayList(data.getDoubleValue("MinCellVolt"),
                    data.getDoubleValue("MaxCellVolt") - data.getDoubleValue("MinCellVolt"),
                    data.getDoubleValue("MinTemp"),
                    data.getDoubleValue("MaxTemp") - data.getDoubleValue("MinTemp")));
        }
        return r;
    }

    private void processAggregationToday(JSONObject r, String filedName, double val, String key) {
        if (r.containsKey(key)) {
            r.getJSONObject(key).put(filedName, val);
        } else {
            JSONObject data = new JSONObject();
            data.put("MinTemp", 0);
            data.put("MaxTemp", 0);
            data.put("MinCellVolt", 0);
            data.put("MaxCellVolt", 0);
            data.put(filedName, val);
            r.put(key, data);
        }
    }

    public JSONObject getTopAndBottom(String id) {
        EquipmentManage equipmentManage = equipmentManageRepository.findOne(id);
        QEquipmentManage qEquipmentManage = QEquipmentManage.equipmentManage;

        ProjectManage projectManage = equipmentManageRepository.query()
                .select(qEquipmentManage.project)
                .from(qEquipmentManage)
                .where(qEquipmentManage.id.eq(id))
                .limit(1)
                .fetchOne();

        List<String> parentIds = equipmentManageRepository.query()
                .select(qEquipmentManage.id)
                .from(qEquipmentManage)
                .where(qEquipmentManage.parent.id.eq(equipmentManage.getId())
                        .and(qEquipmentManage.isValid.eq(1)))
                .fetch();
        List<EquipmentManage> batteryList = equipmentManageRepository.findAll(qEquipmentManage.parent.id.in(parentIds)
                .and(qEquipmentManage.isValid.eq(1))
                .and(qEquipmentManage.equipmentType.eq("4")));
        QEsmsDataBatch qEsmsDataBatch = QEsmsDataBatch.esmsDataBatch;
        Map<String, EquipmentManage> batteryMap = new HashMap<>();
        for (EquipmentManage battery : batteryList) {
            batteryMap.put(battery.getCode().split("#")[1] + "Volt", battery);
        }
        EsmsDataBatch batch = dataBatchRepository.query()
                .select(qEsmsDataBatch)
                .from(qEsmsDataBatch)
                .where(qEsmsDataBatch.type.eq("canbs").and(qEsmsDataBatch.projectIp.eq(projectManage.getIp())))
                .orderBy(qEsmsDataBatch.time.desc())
                .limit(1)
                .fetchOne();
        JSONObject r = new JSONObject();
        JSONObject volt = elasticsearchService.searchByMatchFunctionNews(QueryBuilders.boolQuery()
                .filter(QueryBuilders.prefixQuery("id", batch.getId() + "_")), key -> {
            return batteryMap.containsKey(key);
        });
        volt.remove("time");
        volt.remove("port");
        volt.remove("macid");
        volt.remove("ip");
        r.put("voltage", volt);
        return r;
    }
}
